package com.github.common.extend.demo.config.feign;

import feign.Client;
import feign.Feign;
import feign.Request;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import javax.annotation.Resource;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author wangjj7
 * @date 2024/4/29
 * @description
 */
@Slf4j
@Component
public class FeignProxyBuilder extends Feign.Builder {

    @Resource
    private FeignRequestTimeoutLogProperties timeoutLogProperties;

    @Override
    public Feign.Builder client(Client client) {
        super.client(new FeignRequestTimeoutLogClient(client));
        return this;
    }

    class FeignRequestTimeoutLogClient implements Client{

        private final Client targetClient;

        private final AntPathMatcher antPathMatcher = new AntPathMatcher();

        public FeignRequestTimeoutLogClient(Client targetClient) {
            Objects.requireNonNull(targetClient);
            this.targetClient = targetClient;
        }

        @Override
        public Response execute(Request request, Request.Options options) throws IOException {
            long startTimeMillis = System.currentTimeMillis();
            Response response = targetClient.execute(request, options);
            long timeConsumingMS = System.currentTimeMillis() - startTimeMillis;
            logIfTimeout(request ,timeConsumingMS);
            return response;
        }

        private void logIfTimeout(Request request ,long timeConsumingMS)
        {
            List<FeignRequestTimeoutLogProperties.PathProperties> pathProperties = timeoutLogProperties.getPaths();
            if (CollectionUtils.isNotEmpty(pathProperties)){
                URL url = null;
                try {
                    url = new URL(request.url());
                } catch (MalformedURLException e) {
                    throw new RuntimeException("url is invalid");
                }
                List<FeignRequestTimeoutLogProperties.PathProperties> validPathProperties = pathProperties.stream()
                        .filter(pathProperty -> pathProperty.getTimeoutMs() > 0)
                        .collect(Collectors.toList());

                for (FeignRequestTimeoutLogProperties.PathProperties pathProperty : validPathProperties) {
                    if (StringUtils.equals(pathProperty.getPath() ,url.getPath())){
                        if (timeConsumingMS >= pathProperty.getTimeoutMs()){
                            printLog(request ,timeConsumingMS);
                        }
                        return;
                    }
                }
                for (FeignRequestTimeoutLogProperties.PathProperties pathProperty : validPathProperties) {
                    if (antPathMatcher.match(pathProperty.getPath() ,url.getPath())) {
                        if (timeConsumingMS >= pathProperty.getTimeoutMs()) {
                            printLog(request, timeConsumingMS);
                        }
                        return;
                    }
                }
            }
            Long defaultTimeoutMs = timeoutLogProperties.getDefaultTimeoutMs();
            if (defaultTimeoutMs > 0 && timeConsumingMS > defaultTimeoutMs){
                printLog(request, timeConsumingMS);
                return;
            }
        }
    }

    private void printLog(Request request ,long timeConsumingMS){
        log.error("请求超时，{}毫秒 ，{}" ,timeConsumingMS ,request);
    }

}
